package com.gao.mybatis.executor;

import com.gao.mybatis.configuration.Configuration;
import com.gao.mybatis.configuration.MappedStatement;
import com.gao.mybatis.parse.sql.GenericTokenParser;
import com.gao.mybatis.configuration.ParameterMapping;

import javax.sql.DataSource;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * <p></p>
 *
 * @author GaoShuangWen
 * @since 2020-03-29 18:38
 */
public class DefaultExecutor implements Executor {
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement statement, Object... params) throws Exception {
        DataSource dataSource = configuration.getDataSource();
        Connection connection = dataSource.getConnection();
        String sql = statement.getSql();
        GenericTokenParser parser = new GenericTokenParser("#{", "}");
        String newSql = parser.parse(sql);
        List<ParameterMapping> parameterMappings = parser.getParameterMappings();

        PreparedStatement preparedStatement = connection.prepareStatement(newSql);

        // 反射获取
        String parameterType = statement.getParameterType();

        Class<?> cl = parameterType == null ? null : Class.forName(parameterType);

        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping mapping = parameterMappings.get(i);
            String property = mapping.getProperty();
            assert cl != null;
            Field declaredField = cl.getDeclaredField(property);
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }
        ResultSet resultSet = preparedStatement.executeQuery();


        String resultType = statement.getResultType();

        Class<?> resultCl = resultType == null ? null : Class.forName(resultType);

        assert resultCl != null;
        Object o = resultCl.newInstance();

        List<Object> list = new ArrayList<>();
        while (resultSet.next()) {
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i < metaData.getColumnCount(); i++) {
                String columnName = metaData.getColumnName(i);
                Object val = resultSet.getObject(columnName);
                //使用内省
                PropertyDescriptor descriptor = new PropertyDescriptor(columnName,resultCl);
                Method writeMethod = descriptor.getWriteMethod();
                writeMethod.invoke(o,val);
            }
            list.add(o);
        }

        return (List<E>) list;
    }
}
